﻿using System;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Configuration;
using System.Threading;
using ICSharpCode.SharpZipLib.Zip;

namespace ZipTool
{
    delegate void SetTextCallback(string text);
    public partial class Form1 : Form
    {
        string path = string.Empty;
        public Form1()
        {
            InitializeComponent();

            string filetype = ConfigurationManager.AppSettings["fileType"];
            if (!string.IsNullOrEmpty(filetype))
            {
                FileTypeCombox.DataSource = filetype.Split(',');
            }
            CompressType.SelectedIndex = 0;

        }

        /// <summary>
        /// 选择压缩的路径
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SelectFilePath_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fbd = new FolderBrowserDialog();
            fbd.Description = "请选择文件夹";
            var result = fbd.ShowDialog();
            if (result == DialogResult.OK || result == DialogResult.Yes)
            {
                path = PathLabel.Text = fbd.SelectedPath;
            }
        }

        /// <summary>
        /// 压缩选择路径下的，指定后缀名的文件。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ZipButton_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(path))
            {
                MessageBox.Show("请选择要压缩文件的路径");
                return;
            }
            //获取文件的后缀名
            string filesSuffix = FileTypeCombox.SelectedValue.ToString();

            #region 压缩方式

            string ct = CompressType.SelectedText.ToString();
            ZipEnum zipEnum;
            if (ct.ToLower().Equals("bzip2"))
            {
                zipEnum = ZipEnum.BZIP2;
            }
            else
            {
                zipEnum = ZipEnum.GZIP;
            }
            #endregion

            //是否压缩子文件夹下的文件
            bool isCompressSubfolder = isCompressSub.CheckState == CheckState.Checked;

            Thread zipThread = new Thread(new ParameterizedThreadStart(this.ZipAllFiles));

            ThreadParam param = new ThreadParam();
            param.FilesSuffix = filesSuffix;
            param.FolderPath = path;
            param.IsCompressSubfolder = isCompressSubfolder;
            param.CompressType = zipEnum;

            zipThread.Start(param);
            ZipButton.Text = "压缩中...";
            ZipButton.Enabled = false;

            //ZipAllFiles(param);
        }

        private void ZipAllFiles(object param)
        {
            string folderPath = (param as ThreadParam).FolderPath;
            string filesSuffix = (param as ThreadParam).FilesSuffix;
            bool isCompressSubfolder = (param as ThreadParam).IsCompressSubfolder;
            ZipEnum compressType = (param as ThreadParam).CompressType;

            DirectoryInfo folder = new DirectoryInfo(folderPath);

            var files = folder.GetFiles(filesSuffix, isCompressSubfolder ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);

            if (files.Any())
            {
                foreach (var file in files)
                {
                    //m_SyncContext.Post(AppendTextTologText, file.Name + " start compress...\n");
                    AppendTextTologText(file.FullName + " start compress...\n");
                    var result = ShareZipHelper.ZipSingleFile(file.FullName, file.FullName + ".zip", compressType);
                    if (result)
                    {
                        //m_SyncContext.Post(AppendTextTologText, file.Name + " compress success...\n");
                        AppendTextTologText(file.FullName + " compress success...\n");
                        //删除源文件
                        FileInfo srcFile = new FileInfo(file.FullName);
                        srcFile.Delete();
                    }
                    else
                    {
                        //m_SyncContext.Post(AppendTextTologText, file.Name + " compress failed...\n");
                        AppendTextTologText(file.FullName + " compress failed...\n");
                    }
                }
            }

            //线程结束设置要按钮的状态
            this.ZipButton.Invoke(new Action(()=>{

                this.ZipButton.Text = "压缩";
                this.ZipButton.Enabled = true;
                
            }));

        }

        private void AppendTextTologText(object text)
        {
            if (this.ZipLogText.InvokeRequired)//如果调用控件的线程和创建创建控件的线程不是同一个则为True
            {
                while (!this.ZipLogText.IsHandleCreated)
                {
                    //解决窗体关闭时出现“访问已释放句柄“的异常
                    if (this.ZipLogText.Disposing || this.ZipLogText.IsDisposed)
                        return;
                }
                SetTextCallback d = new SetTextCallback(AppendTextTologText);
                this.ZipLogText.Invoke(d, new object[] { text });
            }
            else
            {
                this.ZipLogText.AppendText(text.ToString());
            }
        }

        private void Program_Exit(object sender, FormClosedEventArgs e)
        {
            Environment.Exit(0);
        }

        private void SelectFileOrPathButton_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();
            var result = dialog.ShowDialog();

            if (result == DialogResult.OK || result == DialogResult.Yes)
            {
                path = FilePathLabel.Text = dialog.SelectedPath;
            }
        }

        private void CompressBtn_Click(object sender, EventArgs e)
        {
            Thread t = new Thread(new ParameterizedThreadStart(CompressFoldeIntoZip));
            ThreadParam param = new ThreadParam();
            param.FolderPath = path;
            param.CompressType = ZipEnum.GZIP;
            t.Start(param);

            CompressBtn.Text = "压缩中...";
            CompressBtn.Enabled = false;
            
        }

        /// <summary>
        /// 把选择的文件夹压缩成一个压缩包
        /// </summary>
        /// <param name="folderName"></param>
        /// <param name="zipEnum"></param>
        /// <returns></returns>
        private void CompressFoldeIntoZip(object param)
        {
            string folderName = (param as ThreadParam).FolderPath;
            ZipEnum zipEnum = (param as ThreadParam).CompressType;
            string zipName = folderName + ".zip";
            ZipFile zipFile = ZipFile.Create(zipName);
            try
            {
                zipFile.BeginUpdate();
                RecursionCompress(ref zipFile, folderName);
                zipFile.CommitUpdate();
            }
            catch (Exception ex)
            {
                AppendTextTologText(zipName + " compress failed...\n");
            }
            finally
            {
                zipFile.Close();
            }

            //更改按钮状态
            this.CompressBtn.Invoke(new Action(() => {

                this.CompressBtn.Text = "压缩";
                this.CompressBtn.Enabled = true;

            }));
        }

        private void RecursionCompress(ref ZipFile zipFile, string folderName)
        {
            //获取path下面的文件
            DirectoryInfo folder = new DirectoryInfo(folderName);
            var files = folder.GetFiles();

            if (files.Any())
            {
                foreach (var file in files)
                {
                    AppendTextTologText(file.FullName + " start compress...\n");
                    zipFile.Add(file.FullName);
                    AppendTextTologText(file.FullName + "compress success...\n");
                }
            }

            //获取下面的文件夹
            var directories = folder.GetDirectories();
            foreach (DirectoryInfo directory in directories)
            {
                zipFile.AddDirectory(directory.FullName);

                RecursionCompress(ref zipFile, directory.FullName);
            }
        }
    }

    public class ThreadParam
    {
        public string FolderPath { set; get; }
        public string FilesSuffix { set; get; }
        public bool IsCompressSubfolder { set; get; }

        public ZipEnum CompressType { set; get; }
    }
}
